package com.micro.magupe.auth.vo;

import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.SpringSecurityCoreVersion;
import org.springframework.security.core.userdetails.UserDetails;

import com.micro.magupe.common.util.CollectionsUtil;

public class UserDetailsImpl implements UserDetails{

	private static final long serialVersionUID = 1L;

    private String username;

    private String name;

    private String password;
    private String clientId;
    private String id;
    public UserDetailsImpl() {
    	this(null, null, true, true, true, true, null);
	}
    
	public UserDetailsImpl(String username, String password, Collection<? extends GrantedAuthority> authorities) {
		this(username, password, true, true, true, true, authorities);
	}
    
	public UserDetailsImpl(String username, String password, boolean enabled,
			boolean accountNonExpired, boolean credentialsNonExpired,
			boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities) {
		
		this.username = username;
		this.password = password;
		this.enabled = enabled;
		this.accountNonExpired = accountNonExpired;
		this.credentialsNonExpired = credentialsNonExpired;
		this.accountNonLocked = accountNonLocked;
		this.authorities = Collections.unmodifiableSet(sortAuthorities(authorities));
	}
	
	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getClientId() {
		return clientId;
	}

	public void setClientId(String clientId) {
		this.clientId = clientId;
	}

	public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username == null ? null : username.trim();
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name == null ? null : name.trim();
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password == null ? null : password.trim();
    }

	private final Set<GrantedAuthority> authorities;
	private final boolean accountNonExpired;
	private final boolean accountNonLocked;
	private final boolean credentialsNonExpired;
	private final boolean enabled;
	
	@Override
	public Collection<? extends GrantedAuthority> getAuthorities() {
		return authorities;
	}

	// 账号是否过期
	@Override
	public boolean isAccountNonExpired() {
		return accountNonExpired;
	}

	// 账号是否锁定
	@Override
	public boolean isAccountNonLocked() {
		return accountNonLocked;
	}

	// 密码是否过期
	@Override
	public boolean isCredentialsNonExpired() {
		return credentialsNonExpired;
	}

	// 账号是否可用
	@Override
	public boolean isEnabled() {
		return enabled;
	}
	
	private static SortedSet<GrantedAuthority> sortAuthorities(Collection<? extends GrantedAuthority> authorities) {
		SortedSet<GrantedAuthority> sortedAuthorities = new TreeSet<GrantedAuthority>(new AuthorityComparator());

		if(!CollectionsUtil.isEmpty(authorities)) {
			for (GrantedAuthority grantedAuthority : authorities) {
				sortedAuthorities.add(grantedAuthority);
			}
			return sortedAuthorities;
		}
		
		return new TreeSet<GrantedAuthority>(new AuthorityComparator());
	}
	
	private static class AuthorityComparator implements Comparator<GrantedAuthority>, Serializable {
		
		private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
		
		public int compare(GrantedAuthority g1, GrantedAuthority g2) {
			if (g2.getAuthority() == null) {
				return -1;
			}

			if (g1.getAuthority() == null) {
				return 1;
			}

			return g1.getAuthority().compareTo(g2.getAuthority());
		}
	}
	
    public static class UserDetailsImplBuilder {
        private UserDetailsImpl userDetails = new UserDetailsImpl();

        public UserDetailsImplBuilder withUsername(String username) {
            userDetails.setUsername(username);
            return this;
        }

        public UserDetailsImplBuilder withPassword(String password) {
            userDetails.setPassword(password);
            return this;
        }

        public UserDetailsImplBuilder withClientId(String clientId) {
            userDetails.setClientId(clientId);
            return this;
        }

        public UserDetailsImplBuilder withUserId(String id) {
            userDetails.setId(id);
            return this;
        }

        public UserDetailsImpl build() {
            return userDetails;
        }
    }
}